// ignore: file_names
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:common_utils/common_utils.dart';
import 'package:crypto/crypto.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart';

import './Message.pb.dart' as Message;
import './ReplyBody.pb.dart' as ReplyBody;
import './SentBody.pb.dart' as SentBody;
import 'package:fixnum/fixnum.dart';
import 'package:convert/convert.dart';

//PONG
// ignore: constant_identifier_names
const PONG_TYPE = 0;
//发送消息类型
// ignore: constant_identifier_names
const Message_TYPE = 2;
//强制下线类型
// ignore: constant_identifier_names
const ACTION_999 = 999;
//响应消息类型
// ignore: constant_identifier_names
const REPLY_BODY = 4;
//消息发送
// ignore: constant_identifier_names
const SEND_BODY = 3;
//PING
// ignore: constant_identifier_names
const PING_TYPE = 1;

// ignore: constant_identifier_names
const DATA_HEADER_LENGTH = 1;

const SOCKET_APP_VERSION = '100';

class CIMSocket extends ChangeNotifier {
  late Socket? socket;
  late String? uri;
  late int? port;
  late int? uid;
  late String endCode = "0";
  final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
  late TimerUtil timer = TimerUtil()
    ..mTotalTime = 10000
    ..setOnTimerTickCallback((millisUntilFinished) {
      connect();
    });
  late bool isConnected = false;

  late Message.Model? model = null;

  Future init(String uri, int port, int uid) async {
    this.uri = uri;
    this.port = port;
    this.uid = uid;
  }

  //登录
  Future connect() async {
    if (uri == null || port == null || uid == null) {
      throw IOException;
    }
    Socket.connect(uri, port!).then((Socket sock) {
      sock.listen((data) async {
        int l = (data[1] & 0xff);
        int h = (data[2] & 0xff);
        int length = (l | h << 8);
        if (data[0] == PING_TYPE) {
          sendPong();
        } else if (data[0] == REPLY_BODY) {
          var message = data.sublist(3, length + 3);
          ReplyBody.Model info = ReplyBody.Model();
          info.mergeFromBuffer(message);
        } else if (data[0] == Message_TYPE) {
          var message = data.sublist(3, length + 3);
          Message.Model model = Message.Model();
          model.mergeFromBuffer(message);
          switchMessage(model);
        }
      }, onError: (error, StackTrace trace) {
        print('CIMSocket error');
        socket = null;
        isConnected = false;
        if (!timer.isActive()) {
          timer.startTimer();
        }
        notifyListeners();
      }, onDone: () {
        print('CIMSocket done');
        socket = null;
        isConnected = false;
        notifyListeners();
        if (endCode != "999") {
          if (!timer.isActive()) {
            timer.startTimer();
          }
        }
      }, cancelOnError: true);
      socket = sock;
      sendLoginMsg();
    }).catchError((e) {
      print('CIMSocket catcherror');
      print('Unable to connect: $e');
      socket = null;
      isConnected = false;
      notifyListeners();
      // Future.delayed(Duration(milliseconds: 3000), () {
      //   connect();
      // });
      if (!timer.isActive()) {
        timer.startTimer();
      }
    });
  }

  //登出
  Future disConnect() async {
    if (socket != null) {
      endCode = '999';
      await socket!.close();
    }
  }

  //发送登录消息
  Future sendLoginMsg() async {
    SystemInfo systemInfo = SystemInfo();
    await systemInfo.init();
    String deviceName = systemInfo.deviceName;
    // DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
    String channel = systemInfo.deviceName;
    String systemVersion = systemInfo.version;
    String deviceId = hex.encode(
        md5.convert(const Utf8Encoder().convert(systemInfo.deviceId)).bytes);

    Map<String, String> map = {
      "uid": uid.toString(), //主id
      "channel": channel,
      "appVersion": SOCKET_APP_VERSION,
      "osVersion": systemVersion,
      "packageName": "cn.asihe.cim",
      "deviceId": deviceId,
      // (await PlatformDeviceId.getDeviceId)!.replaceAll("-", ""), //应用id
      "deviceName": '$deviceName ${systemInfo.model}',
      "language": "zh-CN",
    };
    int time = DateTime.now().millisecondsSinceEpoch;
    Int64 timeStamp = Int64.parseInt(time.toString());
    var body = SentBody.Model(data: map);
    body.key = "client_bind";
    body.timestamp = timeStamp;
    var data = body.writeToBuffer();
    var protobuf = Uint8List(data.length + 3);
    protobuf[0] = 3;
    protobuf[1] = (data.length & 0xff);
    protobuf[2] = ((data.length >> 8) & 0xff);
    protobuf.setRange(3, data.length + 3, data);
    socket!.add(protobuf);
    await socket!.flush();
    print('CIMSocket login finished');
    isConnected = true;
    if (timer.isActive()) {
      timer.cancel();
    }
    notifyListeners();
  }

  /// 发送群组聊天 tag
  Future<int> sendTag(String tag) async {
    Map<String, String> map1 = {"tag": tag};
    int time = DateTime.now().millisecondsSinceEpoch;
    Int64 timeStamp = Int64.parseInt(time.toString());
    var body = SentBody.Model(data: map1);
    body.key = "client_set_tag";
    body.timestamp = timeStamp;
    var data = body.writeToBuffer();
    var protobuf = Uint8List(data.length + 3);
    protobuf[0] = 3;
    protobuf[1] = (data.length & 0xff);
    protobuf[2] = ((data.length >> 8) & 0xff);
    protobuf.setRange(3, data.length + 3, data);
    socket!.add(protobuf);
    await socket!.flush();
    print('CIMSocket bind chattingTag Success!');
    return 2;
  }

//发送PONG响应
  Future sendPong() async {
    var PONG = Uint8List(7);
    var PONG_BODY = Uint8List(4);
    PONG_BODY[0] = 80;
    PONG_BODY[1] = 79;
    PONG_BODY[2] = 78;
    PONG_BODY[3] = 71;
    PONG[0] = PONG_TYPE;
    PONG[1] = (PONG_BODY.length & 0xff);
    PONG[2] = ((PONG_BODY.length >> 8) & 0xff);
    PONG.setRange(3, 6, PONG_BODY);
    socket!.add(PONG);
    await socket!.flush();
    isConnected = true;
    if (timer.isActive()) {
      timer.cancel();
    }
    notifyListeners();
  }

  ///消息分发器
  Future switchMessage(Message.Model model, {bool isHistory = false}) async {
    print(model.toProto3Json());
    model = model;
    notifyListeners();
  }
}

class SystemInfo {
  String deviceName = 'cim_entity';
  String version = '0.0.1';
  String deviceId = 'CIM Entity';
  String model = "10";
  final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();

  Future init() async {
    if (Platform.isAndroid) {
      // Android相关代码
      var value = await deviceInfoPlugin.androidInfo;
      deviceName = 'android';
      version = value.version.release;
      deviceId = value.id;
      model = value.model;
    } else if (Platform.isIOS) {
      // iOS相关代码
      var value = await deviceInfoPlugin.iosInfo;
      deviceName = 'ios';
      version = value.systemVersion!;
      deviceId = value.identifierForVendor!;
      model = value.model!;
    } else if (Platform.isMacOS) {
      // MacOS相关代码
      var value = await deviceInfoPlugin.macOsInfo;

      deviceName = 'macos';
      version = value.kernelVersion;
      deviceId = value.model;
      model = value.model;
    } else if (Platform.isWindows) {
      // Windows相关代码
      var value = await deviceInfoPlugin.windowsInfo;
      deviceName = 'windows';
      version = value.displayVersion;
      deviceId = value.deviceId;
      model = value.majorVersion.toString();
    } else if (Platform.isLinux) {
      // Linux相关代码
      var value = await deviceInfoPlugin.linuxInfo;
      deviceName = 'linux';
      version = value.version!;
      deviceId = value.id;
      model = value.version!;
    }
  }
}
